// This is an open source non-commercial project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com

// ReSharper disable CheckNamespace
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable CommentTypo
// ReSharper disable IdentifierTypo
// ReSharper disable InconsistentNaming
// ReSharper disable StringLiteralTypo
// ReSharper disable UnusedParameter.Local

/*
 * Ars Magna project, http://arsmagna.ru
 */

#region Using directives

using System;
using System.IO;
using System.Xml;
using System.Drawing;
using System.Windows.Forms;

using AM.Reporting.Data;
using AM.Reporting.Table;

#endregion

#nullable enable

namespace AM.Reporting.Import.RDL
{
    /// <summary>
    /// Represents the RDL import plugin.
    /// </summary>
    public partial class RDLImport : ImportBase
    {
        #region Fields

        private ReportPage page;
        private ComponentBase component;
        private Base parent;
        private string defaultFontFamily;
        private BandBase curBand;
        private string dataSetName;
        private bool firstRun;
        private XmlNode reportNode;
        private string filename;
        private float sectionWidth;

        #endregion // Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="RDLImport"/> class.
        /// </summary>
        public RDLImport() : base()
        {
        }

        #endregion // Constructors

        #region Private Methods

        private void LoadBorderColor (XmlNode borderColorNode)
        {
            var nodeList = borderColorNode.ChildNodes;
            foreach (XmlNode node in nodeList)
            {
                if (node.Name == "Default")
                {
                    if (component is ReportComponentBase @base)
                    {
                        @base.Border.Color = UnitsConverter.ConvertColor (node.InnerText);
                    }
                }
                else if (node.Name == "Top")
                {
                    if (component is ReportComponentBase @base)
                    {
                        @base.Border.TopLine.Color =
                            UnitsConverter.ConvertColor (node.InnerText);
                    }
                }
                else if (node.Name == "Left")
                {
                    if (component is ReportComponentBase @base)
                    {
                        @base.Border.LeftLine.Color =
                            UnitsConverter.ConvertColor (node.InnerText);
                    }
                }
                else if (node.Name == "Right")
                {
                    if (component is ReportComponentBase @base)
                    {
                        @base.Border.RightLine.Color =
                            UnitsConverter.ConvertColor (node.InnerText);
                    }
                }
                else if (node.Name == "Bottom")
                {
                    if (component is ReportComponentBase @base)
                    {
                        @base.Border.BottomLine.Color =
                            UnitsConverter.ConvertColor (node.InnerText);
                    }
                }
            }
        }

        private void LoadBorderStyle (XmlNode borderStyleNode)
        {
            var nodeList = borderStyleNode.ChildNodes;
            foreach (XmlNode node in nodeList)
            {
                if (node.Name == "Default")
                {
                    if (component is ReportComponentBase @base)
                    {
                        @base.Border.Lines = BorderLines.All;
                        @base.Border.Style =
                            UnitsConverter.ConvertBorderStyle (node.InnerText);
                    }
                }
                else if (node.Name == "Top")
                {
                    if (component is ReportComponentBase @base)
                    {
                        @base.Border.Lines |= BorderLines.Top;
                        @base.Border.TopLine.Style =
                            UnitsConverter.ConvertBorderStyle (node.InnerText);
                    }
                }
                else if (node.Name == "Left")
                {
                    if (component is ReportComponentBase @base)
                    {
                        @base.Border.Lines |= BorderLines.Left;
                        @base.Border.LeftLine.Style =
                            UnitsConverter.ConvertBorderStyle (node.InnerText);
                    }
                }
                else if (node.Name == "Right")
                {
                    if (component is ReportComponentBase @base)
                    {
                        @base.Border.Lines |= BorderLines.Right;
                        @base.Border.RightLine.Style =
                            UnitsConverter.ConvertBorderStyle (node.InnerText);
                    }
                }
                else if (node.Name == "Bottom")
                {
                    if (component is ReportComponentBase @base)
                    {
                        @base.Border.Lines |= BorderLines.Bottom;
                        @base.Border.BottomLine.Style =
                            UnitsConverter.ConvertBorderStyle (node.InnerText);
                    }
                }
            }
        }

        private void LoadBorderWidth (XmlNode borderWidthNode)
        {
            var nodeList = borderWidthNode.ChildNodes;
            foreach (XmlNode node in nodeList)
            {
                if (node.Name == "Default")
                {
                    if (component is ReportComponentBase @base)
                    {
                        @base.Border.Width = UnitsConverter.SizeToPixels (node.InnerText);
                    }
                }
                else if (node.Name == "Top")
                {
                    if (component is ReportComponentBase @base)
                    {
                        @base.Border.TopLine.Width =
                            UnitsConverter.SizeToPixels (node.InnerText);
                    }
                }
                else if (node.Name == "Left")
                {
                    if (component is ReportComponentBase @base)
                    {
                        @base.Border.LeftLine.Width =
                            UnitsConverter.SizeToPixels (node.InnerText);
                    }
                }
                else if (node.Name == "Right")
                {
                    if (component is ReportComponentBase @base)
                    {
                        @base.Border.RightLine.Width =
                            UnitsConverter.SizeToPixels (node.InnerText);
                    }
                }
                else if (node.Name == "Bottom")
                {
                    if (component is ReportComponentBase @base)
                    {
                        @base.Border.BottomLine.Width =
                            UnitsConverter.SizeToPixels (node.InnerText);
                    }
                }
            }
        }

        private void LoadStyle (XmlNode styleNode)
        {
            var fontStyle = FontStyle.Regular;
            var fontFamily = "Arial";
            var fontSize = 10.0f;
            var paddingTop = 0;
            var paddingLeft = 2;
            var paddingRight = 2;
            var paddingBottom = 0;
            var nodeList = styleNode.ChildNodes;
            foreach (XmlNode node in nodeList)
            {
                if (node.Name == "BorderColor")
                {
                    LoadBorderColor (node);
                }
                else if (node.Name == "BorderStyle")
                {
                    LoadBorderStyle (node);
                }
                else if (node.Name == "BorderWidth")
                {
                    LoadBorderWidth (node);
                }
                else if (node.Name == "BackgroundColor")
                {
                    if (component is ShapeObject shapeObject)
                    {
                        shapeObject.FillColor = UnitsConverter.ConvertColor (node.InnerText);
                    }
                    else if (component is TableObject tableObject)
                    {
                        tableObject.FillColor = UnitsConverter.ConvertColor (node.InnerText);
                    }
                }
                else if (node.Name == "FontStyle")
                {
                    fontStyle = UnitsConverter.ConvertFontStyle (node.InnerText);
                }
                else if (node.Name == "FontFamily")
                {
                    fontFamily = node.InnerText;
                }
                else if (node.Name == "FontSize")
                {
                    fontSize = Convert.ToSingle (UnitsConverter.ConvertFontSize (node.InnerText));
                }
                else if (node.Name == "TextAlign")
                {
                    if (component is TextObject textObject)
                    {
                        textObject.HorizontalAlign = UnitsConverter.ConvertTextAlign (node.InnerText);
                    }
                }
                else if (node.Name == "VerticalAlign")
                {
                    if (component is TextObject textObject)
                    {
                        textObject.VerticalAlign = UnitsConverter.ConvertVerticalAlign (node.InnerText);
                    }
                }
                else if (node.Name == "WritingMode")
                {
                    if (component is TextObject textObject)
                    {
                        textObject.Angle = UnitsConverter.ConvertWritingMode (node.InnerText);
                    }
                }
                else if (node.Name == "Color")
                {
                    if (component is TextObject textObject)
                    {
                        textObject.TextColor = UnitsConverter.ConvertColor (node.InnerText);
                    }
                }
                else if (node.Name == "PaddingLeft")
                {
                    paddingLeft = UnitsConverter.SizeToInt (node.InnerText, SizeUnits.Point);
                }
                else if (node.Name == "PaddingRight")
                {
                    paddingRight = UnitsConverter.SizeToInt (node.InnerText, SizeUnits.Point);
                }
                else if (node.Name == "PaddingTop")
                {
                    paddingTop = UnitsConverter.SizeToInt (node.InnerText, SizeUnits.Point);
                }
                else if (node.Name == "PaddingBottom")
                {
                    paddingBottom = UnitsConverter.SizeToInt (node.InnerText, SizeUnits.Point);
                }
            }

            if (component is TextObject o)
            {
                o.Font = new Font (fontFamily, fontSize, fontStyle);
                o.Padding = new Padding (paddingLeft, paddingTop, paddingRight, paddingBottom);
            }
            else if (component is PictureObject pictureObject)
            {
                pictureObject.Padding =
                    new Padding (paddingLeft, paddingTop, paddingRight, paddingBottom);
            }
        }

        private void LoadVisibility (XmlNode visibilityNode)
        {
            var nodeList = visibilityNode.ChildNodes;
            foreach (XmlNode node in nodeList)
            {
                if (node.Name == "Hidden")
                {
                    component.Visible = !UnitsConverter.BooleanToBool (node.InnerText);
                }
            }
        }

        private void LoadPlotArea (XmlNode plotAreaNode)
        {
            var nodeList = plotAreaNode.ChildNodes;
            foreach (XmlNode node in nodeList)
            {
                if (node.Name == "Style")
                {
                    LoadStyle (node);
                }
            }
        }

        private void LoadSubtotal (XmlNode subtotalNode)
        {
            var nodeList = subtotalNode.ChildNodes;
            foreach (XmlNode node in nodeList)
            {
                if (node.Name == "ReportItems")
                {
                    //LoadReportItems(node);
                }
                else if (node.Name == "Style")
                {
                    LoadStyle (node);
                }
            }
        }

        private void LoadReportItem (XmlNodeList nodeList)
        {
            foreach (XmlNode node in nodeList)
            {
                if (node.Name == "Top")
                {
                    component.Top = UnitsConverter.SizeToPixels (node.InnerText);
                }
                else if (node.Name == "Left")
                {
                    component.Left = UnitsConverter.SizeToPixels (node.InnerText);
                }
                else if (node.Name == "Height")
                {
                    component.Height = UnitsConverter.SizeToPixels (node.InnerText);
                }
                else if (node.Name == "Width")
                {
                    component.Width = UnitsConverter.SizeToPixels (node.InnerText);
                }
                else if (node.Name == "Visibility")
                {
                    LoadVisibility (node);
                }
                else if (node.Name == "Style")
                {
                    LoadStyle (node);
                }
            }

            if (parent is TableCell cell)
            {
                component.Width = cell.Width;
                component.Height = cell.Height;
            }
        }

        private void LoadLine (XmlNode lineNode)
        {
            component = ComponentsFactory.CreateLineObject (lineNode.Attributes["Name"].Value, parent);
            var nodeList = lineNode.ChildNodes;
            LoadReportItem (nodeList);
        }

        private void LoadRectangle (XmlNode rectangleNode)
        {
            var nodeList = rectangleNode.ChildNodes;
            if (RectangleExistReportItem (nodeList))
            {
                LoadContainerRectangle (rectangleNode);
                return;
            }

            component = ComponentsFactory.CreateShapeObject (rectangleNode.Attributes["Name"].Value, parent);
            (component as ShapeObject).Shape = ShapeKind.Rectangle;
            LoadReportItem (nodeList);
            foreach (XmlNode node in nodeList)
            {
                if (node.Name == "ReportItems")
                {
                    LoadReportItems (node);
                }
            }
        }

        private void LoadContainerRectangle (XmlNode rectangleNode)
        {
            var tempParent = parent;
            component = ComponentsFactory.CreateContainerObject (rectangleNode.Attributes["Name"].Value, parent);
            parent = component;
            var nodeList = rectangleNode.ChildNodes;
            (component as ContainerObject).Border.Lines = BorderLines.All;
            (component as ContainerObject).Border.Color = Color.Black;
            LoadReportItem (nodeList);
            foreach (XmlNode node in nodeList)
            {
                if (node.Name == "ReportItems")
                {
                    LoadReportItems (node);
                }
            }

            parent = tempParent;
        }

        private bool RectangleExistReportItem (XmlNodeList reportItemsNode)
        {
            foreach (XmlNode node in reportItemsNode)
            {
                if (node.Name == "ReportItems")
                {
                    foreach (XmlNode itemNode in node)
                    {
                        switch (itemNode.Name)
                        {
                            case "Line":
                            case "Rectangle":
                            case "Textbox":
                            case "Image":
                            case "Subreport":
                            case "Chart":
                            case "Table":
                            case "Matrix":
                                return true;
                        }
                    }
                }
            }

            return false;
        }

        private void LoadParagraphs (XmlNode paragraphs)
        {
            firstRun = true;
            foreach (XmlNode paragraph in paragraphs.ChildNodes)
            {
                if (paragraph.Name == "Paragraph")
                {
                    foreach (XmlNode parChild in paragraph.ChildNodes)
                    {
                        if (parChild.Name == "TextRuns")
                        {
                            foreach (XmlNode runsChild in parChild.ChildNodes)
                            {
                                ParseTextRun (runsChild);
                            }
                        }
                    }
                }

                if (firstRun)
                {
                    firstRun = false;
                }
            }
        }

        private void ParseTextRun (XmlNode runsChild)
        {
            if (runsChild.Name == "TextRun")
            {
                foreach (XmlNode runChild in runsChild.ChildNodes)
                {
                    if (runChild.Name == "Value")
                    {
                        ParseTextBoxValue (runChild);
                    }
                    else if (runChild.Name == "Style")
                    {
                        ParseTextBoxStyle (runChild);
                    }
                }
            }
        }

        private void ParseTextBoxValue (XmlNode runChild)
        {
            if (!firstRun)
            {
                (component as TextObject).Text += "\r\n";
            }

            (component as TextObject).Text += GetValue (runChild.InnerText);
        }

        private void ParseTextBoxStyle (XmlNode runChild)
        {
            var style = FontStyle.Regular;
            var textBoxForeColor = Color.Black;
            var fontFamily = string.Empty;
            var fontSize = 0;
            foreach (XmlNode styleChild in runChild.ChildNodes)
            {
                if (styleChild.Name == "FontFamily")
                {
                    fontFamily = styleChild.InnerText;
                }
                else if (styleChild.Name == "FontSize")
                {
                    int.TryParse (styleChild.InnerText.Replace ("pt", ""), out fontSize);
                }
                else if (styleChild is { Name: "FontWeight", InnerText: "Bold" })
                {
                    style = style | FontStyle.Bold;
                }
                else if (styleChild is { Name: "FontStyle", InnerText: "Italic" })
                {
                    style = style | FontStyle.Italic;
                }
                else if (styleChild is { Name: "TextDecoration", InnerText: "Underline" })
                {
                    style = style | FontStyle.Underline;
                }
                else if (styleChild.Name == "Color")
                {
                    textBoxForeColor = ColorTranslator.FromHtml (styleChild.InnerText);
                }
            }

            if (fontFamily == string.Empty)
            {
                fontFamily = defaultFontFamily;
            }

            if (fontFamily == string.Empty && fontSize == 0)
            {
                (component as TextObject).Font = new Font ((component as TextObject).Font, style);
            }
            else if (fontFamily == string.Empty)
            {
                (component as TextObject).Font = new Font ((component as TextObject).Font.FontFamily, fontSize, style);
            }
            else if (fontSize == 0)
            {
                (component as TextObject).Font = new Font (fontFamily, (component as TextObject).Font.Size, style);
            }
            else
            {
                (component as TextObject).Font = new Font (fontFamily, fontSize, style);
            }

            (component as TextObject).TextColor = textBoxForeColor;
        }

        private string GetValue (string rdlValue)
        {
            //=Fields!VATIdentifierCaption.Value
            var frExpression = "[";
            if (!string.IsNullOrEmpty (rdlValue) && rdlValue[0] == '=') //is expression
            {
                if (rdlValue.IndexOf ("Fields") == 1) //is sumple data source
                {
                    frExpression += dataSetName + ".";

                    var fieldStart = rdlValue.IndexOf ("!") + 1;
                    var fieldEnd = rdlValue.Substring (fieldStart).IndexOf (".") - 1;
                    frExpression += rdlValue.Substring (fieldStart, fieldEnd + 1);
                    frExpression += "]";
                    return frExpression;
                }
            }

            return rdlValue;
        }

        private void LoadTextbox (XmlNode textboxNode)
        {
            if (parent is TableCell cell)
            {
                component = cell;
            }
            else
            {
                component = ComponentsFactory.CreateTextObject (textboxNode.Attributes["Name"].Value, parent);
            }

            var nodeList = textboxNode.ChildNodes;
            LoadReportItem (nodeList);
            foreach (XmlNode node in nodeList)
            {
                if (node.Name == "CanGrow")
                {
                    (component as TextObject).CanGrow = UnitsConverter.BooleanToBool (node.InnerText);
                }
                else if (node.Name == "CanShrink")
                {
                    (component as TextObject).CanShrink = UnitsConverter.BooleanToBool (node.InnerText);
                }
                else if (node.Name == "HideDuplicates")
                {
                    (component as TextObject).Duplicates = Duplicates.Hide;
                }
                else if (node.Name == "Value")
                {
                    (component as TextObject).Text = node.InnerText;
                }
                else if (node.Name == "Paragraphs")
                {
                    LoadParagraphs (node);
                }
            }
        }

        private void LoadImage (XmlNode imageNode)
        {
            component = ComponentsFactory.CreatePictureObject (imageNode.Attributes["Name"].Value, parent);
            var nodeList = imageNode.ChildNodes;
            LoadReportItem (nodeList);
            var name = string.Empty;
            foreach (XmlNode node in nodeList)
            {
                //if (node.Name == "Source")
                //{
                //}
                /*else */
                if (node.Name == "Value")
                {
                    if (File.Exists (node.InnerText))
                    {
                        (component as PictureObject).ImageLocation = node.InnerText;
                    }
                }
                else if (node.Name == "Sizing")
                {
                    (component as PictureObject).SizeMode = UnitsConverter.ConvertSizing (node.InnerText);
                }
            }
        }

        private void LoadSubreport (XmlNode subreportNode)
        {
            component = ComponentsFactory.CreateSubreportObject (subreportNode.Attributes["Name"].Value, parent);
            var subPage = ComponentsFactory.CreateReportPage (Report);
            (component as SubreportObject).ReportPage = subPage;
            var nodeList = subreportNode.ChildNodes;

            var path = Path.GetDirectoryName (filename);
            var reportName = string.Empty;
            foreach (XmlNode node in nodeList)
            {
                if (node.Name == "ReportName")
                {
                    reportName = node.InnerText;
                }
            }

            var subFilename = Path.Combine (path, reportName + ".rdl");
            if (!File.Exists (subFilename))
            {
                subFilename = Path.Combine (path, reportName + ".rdlc");
                if (!File.Exists (subFilename))
                {
                    subFilename = string.Empty;
                }
            }

            if (!string.IsNullOrEmpty (subFilename))
            {
                var doc = new XmlDocument();
                doc.Load (subFilename);
                reportNode = doc.LastChild;
                var tempPage = page;
                page = subPage;
                LoadReport (reportNode);
                page = tempPage;
            }
            else
            {
                var subBand = ComponentsFactory.CreateDataBand (subPage);
                subBand.Height = 2.0f * Utils.Units.Centimeters;
                LoadReportItem (nodeList);
            }
        }

        partial void LoadChart (XmlNode chartNode);

        private void LoadReportItems (XmlNode reportItemsNode)
        {
            var nodeList = reportItemsNode.ChildNodes;
            foreach (XmlNode node in nodeList)
            {
                if (node.Name == "Line")
                {
                    LoadLine (node);
                }
                else if (node.Name == "Rectangle")
                {
                    LoadRectangle (node);
                }
                else if (node.Name == "Textbox")
                {
                    LoadTextbox (node);
                }
                else if (node.Name == "Image")
                {
                    LoadImage (node);
                }
                else if (node.Name == "Subreport")
                {
                    LoadSubreport (node);
                }
                else if (node.Name == "Chart")
                {
                    LoadChart (node);
                }
                else if (node.Name == "Table" || (node.Name == "Tablix" && !IsTablixMatrix (node)))
                {
                    LoadTable (node);
                }
                else if (node.Name == "Matrix" || (node.Name == "Tablix" && IsTablixMatrix (node)))
                {
                    LoadMatrix (node);
                }
            }
        }

        private void LoadBody (XmlNode bodyNode)
        {
            parent = ComponentsFactory.CreateDataBand (page);
            curBand = (BandBase)parent;
            var nodeList = bodyNode.ChildNodes;
            foreach (XmlNode node in nodeList)
            {
                if (node.Name == "ReportItems")
                {
                    LoadReportItems (node);
                }
                else if (node.Name == "Height")
                {
                    (parent as DataBand).Height = UnitsConverter.SizeToPixels (node.InnerText);
                }
            }
        }

        private void LoadPageSection (XmlNode pageSectionNode)
        {
            if (pageSectionNode.Name == "PageHeader")
            {
                page.PageHeader = new PageHeaderBand();
                page.PageHeader.CreateUniqueName();
                page.PageHeader.PrintOn = PrintOn.EvenPages | PrintOn.OddPages | PrintOn.RepeatedBand;
                var nodeList = pageSectionNode.ChildNodes;
                foreach (XmlNode node in nodeList)
                {
                    if (node.Name == "Height")
                    {
                        page.PageHeader.Height = UnitsConverter.SizeToPixels (node.InnerText);
                    }
                    else if (node.Name == "PrintOnFirstPage")
                    {
                        if (node.InnerText == "true")
                        {
                            page.PageHeader.PrintOn |= PrintOn.FirstPage;
                        }
                    }
                    else if (node.Name == "PrintOnLastPage")
                    {
                        if (node.InnerText == "true")
                        {
                            page.PageHeader.PrintOn |= PrintOn.LastPage;
                        }
                    }
                    else if (node.Name == "ReportItems")
                    {
                        parent = page.PageHeader;
                        LoadReportItems (node);
                    }
                }
            }
            else if (pageSectionNode.Name == "PageFooter")
            {
                page.PageFooter = new PageFooterBand();
                page.PageFooter.CreateUniqueName();
                page.PageFooter.PrintOn = PrintOn.EvenPages | PrintOn.OddPages | PrintOn.RepeatedBand;
                var nodeList = pageSectionNode.ChildNodes;
                foreach (XmlNode node in nodeList)
                {
                    if (node.Name == "Height")
                    {
                        page.PageFooter.Height = UnitsConverter.SizeToPixels (node.InnerText);
                    }
                    else if (node.Name == "PrintOnFirstPage")
                    {
                        if (node.InnerText == "true")
                        {
                            page.PageFooter.PrintOn |= PrintOn.FirstPage;
                        }
                    }
                    else if (node.Name == "PrintOnLastPage")
                    {
                        if (node.InnerText == "true")
                        {
                            page.PageFooter.PrintOn |= PrintOn.LastPage;
                        }
                    }
                    else if (node.Name == "ReportItems")
                    {
                        parent = page.PageFooter;
                        LoadReportItems (node);
                    }
                }
            }
        }

        private void LoadPage (XmlNode pageNode)
        {
            var nodeList = pageNode.ChildNodes;
            var pageWidthLoaded = false;
            foreach (XmlNode node in nodeList)
            {
                if (node.Name == "PageHeader")
                {
                    LoadPageSection (node);
                }
                else if (node.Name == "PageFooter")
                {
                    LoadPageSection (node);
                }
                else if (node.Name == "PageHeight")
                {
                    page.PaperHeight = UnitsConverter.SizeToMillimeters (node.InnerText);
                }
                else if (node.Name == "PageWidth")
                {
                    page.PaperWidth = UnitsConverter.SizeToMillimeters (node.InnerText);
                    pageWidthLoaded = true;
                }
                else if (node.Name == "LeftMargin")
                {
                    page.LeftMargin = UnitsConverter.SizeToMillimeters (node.InnerText);
                }
                else if (node.Name == "RightMargin")
                {
                    page.RightMargin = UnitsConverter.SizeToMillimeters (node.InnerText);
                }
                else if (node.Name == "TopMargin")
                {
                    page.TopMargin = UnitsConverter.SizeToMillimeters (node.InnerText);
                }
                else if (node.Name == "BottomMargin")
                {
                    page.BottomMargin = UnitsConverter.SizeToMillimeters (node.InnerText);
                }
                else if (node.Name == "Style")
                {
                    LoadStyle (node);
                }
            }

            if (!pageWidthLoaded && sectionWidth > 0)
            {
                page.PaperWidth = page.LeftMargin + sectionWidth + page.RightMargin;
            }
        }

        private void LoadParameters (XmlNode parametersNode)
        {
            foreach (XmlNode node in parametersNode.ChildNodes)
            {
                var parameter = ComponentsFactory.CreateParameter (node.Attributes["Name"].Value, Report);
                foreach (XmlNode subNode in node.ChildNodes)
                {
                    if (subNode.Name == "DataType")
                    {
                        var type = Type.GetType ("System." + subNode.InnerText);
                        if (type != null)
                        {
                            parameter.DataType = type;
                        }
                        else if (subNode.InnerText == "Integer")
                        {
                            parameter.DataType = typeof (int);
                        }
                        else if (subNode.InnerText == "Float")
                        {
                            parameter.DataType = typeof (float);
                        }
                    }
                    else if (subNode.Name == "Prompt")
                    {
                        parameter.Description = subNode.InnerText;
                    }
                    else if (subNode.Name == "DefaultValue")
                    {
                    }
                }
            }
        }

        private XmlNode GetEmbededImageNode (string objectName)
        {
            foreach (XmlNode node in reportNode.ChildNodes)
            {
                if (node.Name == "EmbeddedImages")
                {
                    foreach (XmlNode embededImage in node.ChildNodes)
                    {
                        if (embededImage.Attributes[0].InnerText == objectName)
                        {
                            return embededImage;
                        }
                    }
                }
            }

            return null;
        }

        private void LoadReport (XmlNode reportNode)
        {
            var pageNbr = 0;
            var nodeList = reportNode.ChildNodes;
            foreach (XmlNode node in nodeList)
            {
                if (node.Name == "Description")
                {
                    Report.ReportInfo.Description = node.InnerText;
                }
                else if (node.Name == "Author")
                {
                    Report.ReportInfo.Author = node.InnerText;
                }
                else if (node.Name == "Body")
                {
                    if (page == null)
                    {
                        page = ComponentsFactory.CreateReportPage (Report);
                    }

                    LoadBody (node);
                }
                else if (node.Name == "Page")
                {
                    if (pageNbr > 0)
                    {
                        page = ComponentsFactory.CreateReportPage (Report);
                    }

                    LoadPage (node);
                    pageNbr++;
                }
                else if (node.Name == "ReportSections")
                {
                    if (node.HasChildNodes && node.FirstChild.Name == "ReportSection")
                    {
                        foreach (XmlNode sectionItem in node.FirstChild)
                        {
                            if (sectionItem.Name == "Body")
                            {
                                if (page == null)
                                {
                                    page = ComponentsFactory.CreateReportPage (Report);
                                }

                                LoadBody (sectionItem);
                            }
                            else if (sectionItem.Name == "Page")
                            {
                                if (pageNbr > 0)
                                {
                                    page = ComponentsFactory.CreateReportPage (Report);
                                }

                                LoadPage (sectionItem);
                                pageNbr++;
                            }
                            else if (sectionItem.Name == "Width")
                            {
                                sectionWidth = UnitsConverter.SizeToMillimeters (sectionItem.InnerText);
                            }
                        }
                    }
                }
                else if (node.Name == "df:DefaultFontFamily")
                {
                    defaultFontFamily = node.InnerText;
                }
                else if (node.Name == "DataSets")
                {
                    if (node.HasChildNodes)
                    {
                        dataSetName = node.FirstChild.Attributes["Name"].Value;
                    }
                }
                else if (node is { Name: "ReportParameters", HasChildNodes: true })
                {
                    LoadParameters (node);
                }
            }

            if (page == null)
            {
                page = ComponentsFactory.CreateReportPage (Report);
                LoadPage (reportNode);
            }
        }

        #endregion // Private Methods

        #region Public Methods

        /// <inheritdoc/>
        public override void LoadReport (Report report, string filename)
        {
            this.filename = filename;
            using (var fs = new FileStream (filename, FileMode.Open, FileAccess.Read))
            {
                LoadReport (report, fs);
            }
        }

        /// <inheritdoc />
        public override void LoadReport (Report report, Stream content)
        {
            Report = report;
            Report.Clear();
            var document = new XmlDocument();
            document.Load (content);
            reportNode = document.LastChild;
            defaultFontFamily = "";
            page = null;
            LoadReport (reportNode);
        }

        #endregion // Public Methods
    }
}
